package server;

//import java.io.PipedInputStream;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;

import obj.Piped;
import objects.Client;
import algo.AlgorythmManager;
import xmlparser.XmlParser;

//Not implement runnable on which threads share the same object instance !
public class MessageReader extends Thread{

	private Client client = new Client() ;
    private AlgorythmManager algom = new AlgorythmManager() ;

    private String AlgorithmSelected;
    private SocketAddress cliSocAdd;
    private DatagramChannel udpchannel;
//    private PipedInputStream is ;
    private byte[] wBuffer ;
    private Piped pipeObj ;
    private int random ;

    //while true thread is alive
	private boolean state = true;
	
    /**
     * Resize my array to get the only filled data but is not optimized
     * @param Byte[] old array
     * @param integer newsize
     * @return Byte[] newArray
     */
	public byte[] resizeArray(byte[] array, int oldSize){
		int j=0;
		//count the number of filled box
		for(int i = 0 ; i<oldSize && array[i] !=0 ; i++){
			j++;
		}
		//the resize with the length
		byte[] tmpArray = new byte[j];
		for(int i = 0 ; i<j ; i++){
			tmpArray[i] = array[i];
		}
		return tmpArray;
	}
	// Resize the entire object		
	//	private static Object resizeArray (Object oldArray, int newSize) {
	//	int oldSize = java.lang.reflect.Array.getLength(oldArray);
	//	Class elementType = oldArray.getClass().getComponentType();
	//	Object newArray = java.lang.reflect.Array.newInstance(elementType,newSize);
	//	int preserveLength = Math.min(oldSize,newSize);
	//	if (preserveLength > 0)
	//		System.arraycopy (oldArray,0,newArray,0,preserveLength);
	//	return newArray; 
	//}
    
    /**
     * Constructor
     * @param udpchannel
     * @param SocketAddress of the client
     * @param byte[] buffer received
     * @param Piped
     */
    public MessageReader(DatagramChannel udpchannel, SocketAddress cliSocAdd , byte[] wBuffer, Piped pipeObj, int random){
    	//super("MessageReader");
        //
        //this.wBuffer= packet.getData();
        //resize data in order to get the right buffer
        this.wBuffer= resizeArray(wBuffer,wBuffer.length);
        this.udpchannel = udpchannel;
        this.cliSocAdd = cliSocAdd;
        this.pipeObj = pipeObj;

        //Fill more data in it
        //de l'algorithme
        this.client.setIdCarte("large.jpg");
        
        this.client.setPort(((InetSocketAddress)cliSocAdd).getPort());
        this.client.setIp(((InetSocketAddress)cliSocAdd).getAddress());
        this.random = random; 
    }

    /**
     * End the thread state
     */
    public void endState() {
		this.state = false;
	}

    /**
     * Run method
     */
	public void run(){
        //increase the thread numbers
        Oserver.incNbMobileThread();
        System.out.println("M : A new mobile ask for positionning: "+ this.client.getIp()+ " , phone number : " + Oserver.getNbMobileThread()  );
        
//        boolean justcreated = true;
        
        while(state){

//        	if (justcreated){
	            //Fill the object client
	            try {
					XmlParser.convertReceivedXmlBytesToObject(wBuffer, client);
//					justcreated = false;
				} catch (SAXException e) {
					System.out.println("The received file is not valid. Please check the sent xml.");
					e.printStackTrace();
					state=false;
					break;
				} catch (Exception e) {
					e.printStackTrace();
				}
		        //set thread name
		        this.setName(client.getCliMac()) ;
		        System.out.println("M : Mobile Mac is : "+ this.getName() );
//		    }else{
//
//        		try {
//					int nb = pipeObj.getIs().read(wBuffer);
//					System.out.println("M : Received packet from old client... "+ nb +" "+ wBuffer.toString());
//
//				} catch (IOException e) {
//					// TODO Auto-generated catch block
//					e.printStackTrace();
//				}
//		    }
        	
        	//////////////////For testing purpose use this method
//            ArrayList<ReferencePoint> referencePoints = ReferencePointsDAO.read();
//    		HashMap<String, Measurement> measurements = referencePoints.get(random).getMeasurements();
//    		client.setMeasurements(measurements);
    		///////////////////
    		
    		//if the buffer is not null
    		//TODO 

//    		if (wBuffer[0] != -1){
            //fill characteristics

            	this.AlgorithmSelected =client.getAlgorithm() ;
				System.out.println("M : Running algorithm selected by the client : " + AlgorithmSelected);
				
	            //client must be filled by the algorithm
//				if ( AlgorithmSelected == "FRBHM"){
					algom.frbhm(client);
//				}else if ( AlgorithmSelected == ""){
//				}else if ( AlgorithmSelected == ""){
//				}

	            // Create new object to convert into xml result

	            //Algorithm done
	            System.out.println("M : Computed.");
	
	            //Convert the filled object to XML files
	            Document dom = XmlParser.convertObjectToDocument(client);
	            byte[] tmpToSend = XmlParser.DocToBuffer(dom);
	            //Convert it and save into the buffer in order to use ByteBuffer
	            ByteBuffer toSend =  ByteBuffer.wrap(tmpToSend);
	            
	            //send the bytebuffer
	            ServerMain.sendpacket(udpchannel,cliSocAdd, toSend);

	            //response send
	            this.pipeObj.setResponseSent();
	            
	            System.out.println( "M : Results sent.");

//	        }else state = false;
//If the above comment is uncomment, comment the following in order to activate thread manager    		
    		state=false;
        }
        
        System.out.println( "M : Thread answered to phone : " + client.getCliMac() +" and ends this session." );
//        try {
//        	//close the inputstream first
//			this.is.close();
//		} catch (IOException e) {
//			e.printStackTrace();
//			System.out.println("M : InputStream already close.");
//		}
		
		//decrease the number of phone
        Oserver.decNbMobileThread();
        System.out.println("M : Thread ends.");
	}	
}